﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using NHibernate;
using System.Web.Mvc;

namespace BeardCoder.Data.Framework.NHibernate
{
    public class SessionHttpModule : IHttpModule
    {
        #region Implements IHttpModule interface

        public void Init(HttpApplication context)
        {
            context.BeginRequest += ContextBeginRequest;
            context.EndRequest += ContextEndRequest;
            context.Error += ContextError;
        }

        public void Dispose() { }

        #endregion

        #region Private methods

        private void ContextBeginRequest(object sender, EventArgs e)
        {
            foreach (var sessionFactory in GetSessionFactories())
            {
                var localFactory = sessionFactory;

                LazySessionContext.Bind(new Lazy<ISession>(() => BeginSession(localFactory)), sessionFactory);
            }
        }

        private void ContextEndRequest(object sender, EventArgs e)
        {
            foreach (var sessionfactory in GetSessionFactories())
            {
                var session = LazySessionContext.UnBind(sessionfactory);
                if (session == null) continue;
                EndSession(session);
            }
        }

        private void ContextError(object sender, EventArgs e)
        {
            foreach (var sessionfactory in GetSessionFactories())
            {
                var session = LazySessionContext.UnBind(sessionfactory);
                if (session == null) continue;
                EndSession(session, false);
            }
        }

        /// <summary>
        /// Retrieves all ISessionFactory instances via IoC
        /// </summary>
        private IEnumerable<ISessionFactory> GetSessionFactories()
        {
            var sessionFactories = DependencyResolver.Current.GetServices<ISessionFactory>();

            if (sessionFactories == null || !sessionFactories.Any())
                throw new TypeLoadException("At least one ISessionFactory has not been registered with IoC");

            return sessionFactories;
        }

        #endregion

        #region Static private methods

        private static ISession BeginSession(ISessionFactory sessionFactory)
        {
            var session = sessionFactory.OpenSession();
            //session.BeginTransaction();
            return session;
        }

        private static void EndSession(ISession session, bool commitTransaction)
        {
            try
            {
                //if (session.Transaction != null && session.Transaction.IsActive)
                //{
                //    if (commitTransaction)
                //    {
                //        try
                //        {
                //            session.Transaction.Commit();
                //        }
                //        catch
                //        {
                //            session.Transaction.Rollback();
                //            throw;
                //        }
                //    }
                //    else
                //    {
                //        session.Transaction.Rollback();
                //    }
                //}
            }
            finally
            {
                if (session.IsOpen)
                    session.Close();

                session.Dispose();
            }
        }

        private static void EndSession(ISession session)
        {
            EndSession(session, true);
        }

        #endregion
    }
}
